package com.yunke.common.log;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 云科搭子系统日志切面
 * 
 * @author yunke
 * @since 1.0.0
 */
@Slf4j
@Aspect
@Component
public class YunkeLogAspect {

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 定义切点：所有Controller层的方法
     */
    @Pointcut("execution(public * com.yunke.controller.*.*(..))")
    public void controllerLog() {
    }

    /**
     * 定义切点：所有Service层的方法
     */
    @Pointcut("execution(public * com.yunke.service.*.*(..))")
    public void serviceLog() {
    }

    /**
     * 前置通知：记录请求信息
     */
    @Before("controllerLog()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            
            // 记录请求信息
            log.info("========== 请求开始 ==========");
            log.info("请求URL: {}", request.getRequestURL().toString());
            log.info("请求方法: {}", request.getMethod());
            log.info("请求IP: {}", getClientIpAddress(request));
            log.info("请求类方法: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
            log.info("请求参数: {}", Arrays.toString(joinPoint.getArgs()));
            
            // 记录请求头信息（开发环境）
            if (log.isDebugEnabled()) {
                Map<String, String> headers = getRequestHeaders(request);
                log.debug("请求头信息: {}", toJsonString(headers));
            }
        }
    }

    /**
     * 环绕通知：记录执行时间和响应信息
     */
    @Around("controllerLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        
        try {
            result = proceedingJoinPoint.proceed();
            long endTime = System.currentTimeMillis();
            
            log.info("响应结果: {}", toJsonString(result));
            log.info("执行时间: {}ms", endTime - startTime);
            log.info("========== 请求结束 ==========");
            
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("请求异常: {}", e.getMessage());
            log.error("执行时间: {}ms", endTime - startTime);
            log.error("========== 请求异常结束 ==========");
            throw e;
        }
    }

    /**
     * 异常通知：记录异常信息
     */
    @AfterThrowing(pointcut = "controllerLog()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        log.error("方法: {}.{} 发生异常", 
                 joinPoint.getSignature().getDeclaringTypeName(), 
                 joinPoint.getSignature().getName());
        log.error("异常信息: ", e);
    }

    /**
     * 环绕通知：记录Service层方法执行时间
     */
    @Around("serviceLog()")
    public Object doServiceAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String className = proceedingJoinPoint.getTarget().getClass().getSimpleName();
        String methodName = proceedingJoinPoint.getSignature().getName();
        
        try {
            Object result = proceedingJoinPoint.proceed();
            long endTime = System.currentTimeMillis();
            
            // 只记录执行时间超过1秒的方法
            if (endTime - startTime > 1000) {
                log.warn("慢查询 - {}.{} 执行时间: {}ms", className, methodName, endTime - startTime);
            } else if (log.isDebugEnabled()) {
                log.debug("Service方法 - {}.{} 执行时间: {}ms", className, methodName, endTime - startTime);
            }
            
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("Service异常 - {}.{} 执行时间: {}ms, 异常: {}", 
                     className, methodName, endTime - startTime, e.getMessage());
            throw e;
        }
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        String proxyClientIp = request.getHeader("Proxy-Client-IP");
        if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
            return proxyClientIp;
        }
        
        String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
        if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
            return wlProxyClientIp;
        }
        
        return request.getRemoteAddr();
    }

    /**
     * 获取请求头信息
     */
    private Map<String, String> getRequestHeaders(HttpServletRequest request) {
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            
            // 过滤敏感信息
            if ("authorization".equalsIgnoreCase(headerName) || 
                "cookie".equalsIgnoreCase(headerName) ||
                "token".equalsIgnoreCase(headerName)) {
                headerValue = "***";
            }
            
            headers.put(headerName, headerValue);
        }
        
        return headers;
    }

    /**
     * 对象转JSON字符串
     */
    private String toJsonString(Object object) {
        if (object == null) {
            return "null";
        }
        
        try {
            return objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            log.warn("对象转JSON失败: {}", e.getMessage());
            return object.toString();
        }
    }
} 